﻿using System;
using System.Threading.Tasks;
using AutoFixture.Xunit2;
using Sustainalytics.Auth.Common;
using Sustainalytics.Auth.Service.GA;
using Sustainalytics.Auth.Service.Properties;
using Sustainalytics.Entities;
using Xunit;

namespace Sustainalytics.Auth.Service.Tests
{
    [Trait("Category", "Unit")]
    public class Get_token_with_refresh_token_should : IClassFixture<TokenServer>
    {
        private readonly TokenServer tokenServer;

        public Get_token_with_refresh_token_should(TokenServer tokenServer)
        {
            this.tokenServer = tokenServer;
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_client_id_is_not_sent(string refreshToken)
        {
            var response = await tokenServer.GetReponseByRefreshTokenAsync(null, refreshToken);

            response.ShouldBeErrorResponse(Resources.MissingClientId);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_client_id_is_invalid(string refreshToken)
        {
            var response = await tokenServer.GetReponseByRefreshTokenAsync("invalid client_id", refreshToken);

            response.ShouldBeErrorResponse(Resources.InvalidClientId);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_user_is_not_found(string username, string password)
        {
            SetFakeUserUsedToGetANewTokenUsingTheRefreShToken(username, null);
            SetFakeUserUsedToGetTheRefreshToken(username, password);

            var refreshToken = await tokenServer.GetRefreshTokenAsync(username, password);
            var response = await tokenServer.GetReponseByRefreshTokenAsync("clientId1", refreshToken);

            response.ShouldBeErrorResponse(Resources.WrongEmail, Resources.UserNotFound);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_user_is_not_active(string username, string password)
        {
            SetFakeUserUsedToGetANewTokenUsingTheRefreShToken(username, new GaUser { Status = Status.Inactive });
            SetFakeUserUsedToGetTheRefreshToken(username, password);

            var refreshToken = await tokenServer.GetRefreshTokenAsync(username, password);
            var response = await tokenServer.GetReponseByRefreshTokenAsync("clientId1", refreshToken);

            response.ShouldBeErrorResponse(Resources.InactiveAccount, Resources.InactiveAccountMessage);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_legal_agreement_is_not_accepted(string username, string password)
        {
            SetFakeUserUsedToGetANewTokenUsingTheRefreShToken(username, new GaUser
            {
                Username = username,
                Password = PasswordManager.HashPassword(password),
                PasswordExpirationDate = DateTime.UtcNow.AddDays(1),
            });
            SetFakeUserUsedToGetTheRefreshToken(username, password);

            var refreshToken = await tokenServer.GetRefreshTokenAsync(username, password);
            var response = await tokenServer.GetReponseByRefreshTokenAsync("clientId1", refreshToken);

            response.ShouldBeErrorResponse(Resources.ClientLegalAgreementNotAccepted, Resources.LegalAgreementWarning);
        }

        [Theory, AutoData]
        public async Task return_token_when_user_is_valid(string username, string password)
        {
            SetFakeUserUsedToGetANewTokenUsingTheRefreShToken(username, CreateActiveGaUser(username, password));
            SetFakeUserUsedToGetTheRefreshToken(username, password);

            var refreshToken = await tokenServer.GetRefreshTokenAsync(username, password);
            var response = await tokenServer.GetReponseByRefreshTokenAsync("clientId1", refreshToken);

            response.ShouldBeTokenResponse();
        }

        private void SetFakeUserUsedToGetANewTokenUsingTheRefreShToken(string username, GaUser gaUser)
            => tokenServer.SetFakeGaUser(username, gaUser);

        private void SetFakeUserUsedToGetTheRefreshToken(string username, string password)
            => tokenServer.SetFakeGaUser(username, CreateActiveGaUser(username, password));

        private static GaUser CreateActiveGaUser(string username, string password)
            => TokenServer.CreateActiveGaUser(username, password);
    }
}
